#pragma once

#include "Socket.hpp"

#include <memory>
#include <unistd.h>
#include <sys/poll.h>
#include <iostream>

using namespace SocketModule;

class PollServer
{
    static const int size = 4096;
    static const int defaultfd = -1;

public:

    PollServer(int port)
        :_listenSockfd(std::make_unique<TcpSocket>())
        ,_isRunning(false)
    {
        _listenSockfd->buildTcpSocketMethod(port);

        for (int i = 0; i < size; ++i)
        {
            _fds[i].fd = defaultfd;
            _fds[i].events = 0;
            _fds[i].revents = 0;
        }

        _fds[0].fd = _listenSockfd->getFd();
        _fds[0].events = POLLIN;
    }

    void start()
    {
        int timeout = -1;
        _isRunning = true;
        while (_isRunning)
        {
            // listenSockfd 自己的 IO 也应该放入 Poll ，让 OS 去通知 listenSockfd 的读事件
            printFd();

            int n = ::poll(_fds, size, timeout);

            switch (n)
            {
            case -1:
                LOG(LogLevel::ERROR) << "poll error";
                break;
            case 0:
                LOG(LogLevel::INFO) << "time out...";
                break;
            default:
                LOG(LogLevel::DEBUG) << "有事件就绪了... 数量:" << n;
                dispatcher();        // 事件派发
                break;
            }
        }
    }


    void dispatcher()                    // 事件派发，分为 读新链接 和 读普通事件
    {
        for (int i = 0; i < size; ++i)
        {
            if (_fds[i].fd == defaultfd)
            {
                continue;
            }

            if (_fds[i].revents & POLLIN)
            {

                if (_fds[i].fd == _listenSockfd->getFd())
                {
                    accepter();      // 处理新链接
                }
                else
                {
                    recver(i);       // 普通的读事件
                }
            }

            // if (_fds[i].revent & POLLOUT)
            // {

            // }
        }
    }

    void accepter()
    {
        InetAddr client;
        int sockfd = _listenSockfd->acceptFd(client);   // 这里 accept 不会阻塞
        if (sockfd < 0)
        {
            return;
        }

        LOG(LogLevel::DEBUG) << "get new link, sockfd:" << sockfd << " client:" << client.getStringAddr();
        
        int pos = 0;
        while (pos < size)                          // 寻找空位
        {
            if (_fds[pos].fd == defaultfd)
            {
                break;
            }
            ++pos;
        }
        if (pos == size)                          // 满了直接关闭
        {
            LOG(LogLevel::WARNING) << "poll server full";
            ::close(sockfd);
        }
        else
        {
            _fds[pos].fd = sockfd;                // 注册 sockfd
            _fds[pos].events = POLLIN;
            _fds[pos].revents = 0;
            LOG(LogLevel::DEBUG) << "register fd success";
        }
    }

    void recver(int pos)
    {
        char buf[1024];
        ssize_t n = recv(_fds[pos].fd, buf, sizeof(buf) - 1, 0);          // 不会阻塞
        if (n > 0)
        {
            buf[n] = 0;
            std::cout << "client say#" << buf << std::endl;     // 打印字符串信息
        }
        else if (n == 0)
        {
            LOG(LogLevel::DEBUG) << "client quit...";

            _fds[pos].fd = defaultfd;               // 注销 fd
            _fds[pos].events = 0;
            _fds[pos].revents = 0;
            ::close(_fds[pos].fd);                  // 并关闭
        }
        else
        {
            LOG(LogLevel::ERROR) << "recv failure";

            _fds[pos].fd = defaultfd;               // 注销 fd
            _fds[pos].events = 0;
            _fds[pos].revents = 0;
            ::close(_fds[pos].fd);                  // 并关闭
        }
    }

    void printFd()
    {
        std::cout << "_fds: ";
        for (int i = 0; i < size; ++i)
        {
            if (_fds[i].fd == defaultfd)
            {
                continue;
            }
            std::cout << _fds[i].fd << " ";
        }
        std::cout << std::endl;
    }

    void stop()
    {
        _isRunning = false;
    }

    ~PollServer()
    {
        ;
    }

private:

    std::unique_ptr<Socket> _listenSockfd;
    bool _isRunning;

    struct pollfd _fds[PollServer::size];
};
